﻿using PBO.Data.SQLite;
using PBO.Data.Util;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Serialization;

namespace PBO.Data.PokemonOnline
{
    public static class POHelper
    {

        private static readonly StatType[] PO_STATS = { StatType.Hp, StatType.Atk, StatType.Def, StatType.SpAtk, StatType.SpDef, StatType.Speed };

        public static TeamData ReadFile(string path)
        {
            TeamData data = null;
            var team = ReadPOFile(path);
            if (team != null)
            {
                data = ToPBO(team);
            }
            return data;
        }

        public static Team ReadPOFile(string path)
        {
            Team team = null;
            try
            {
                using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read))
                {
                    var xs = new XmlSerializer(typeof(Team));
                    team = (Team)xs.Deserialize(fs);
                    fs.Close();
                }
            }
            catch { }
            return team;
        }

        public static void WriteFile(string path, Team team)
        {
            try
            {
                using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write))
                {
                    var xs = new XmlSerializer(typeof(Team));
                    xs.Serialize(fs, team);
                    fs.Close();
                }
            }
            catch { }
        }

        public static void WriteFile(string path, TeamData team)
        {
            WriteFile(path, ToPO(team));
        }

        public static Team ToPO(TeamData data)
        {
            var team = new Team();
            team.Pokemons = data.Pokemons.Select(p => p.ToPokemon()).ToArray();
            return team;
        }

        public static TeamData ToPBO(Team team)
        {
            TeamData data = new TeamData();
            for (int i = 0; i < data.Pokemons.Length && i < team.Pokemons.Length; i++)
            {
                data.Pokemons[i] = team.Pokemons[i].ToInfo();
            }
            return data;
        }

        public static PokemonCustomInfo ToInfo(this Pokemon pm)
        {
            var data = SQLiteHelper.Pokemon.GetModel(pm.Num, pm.Forme);
            if (data == null) return PokemonCustomInfo.EmptyPokemon;
            var info = new PokemonCustomInfo();
            info.Identity = data.Id;
            info.NickName = pm.Nickname;
            info.Ability = (Trait)pm.Ability;
            info.Item = SQLiteHelper.Item.GetByPOId(pm.Item).Item;
            info.Gender = (PokemonGender)pm.Gender;
            info.LV = (byte)pm.Lvl;
            info.Nature = (PokemonNature)pm.Nature;
            info.Moves = pm.Move;
            for (int i = 0; i < pm.EV.Length && i < PO_STATS.Length; i++)
            {
                info.Ev[PO_STATS[i]] = pm.EV[i];
            }
            for (int i = 0; i < pm.DV.Length && i < PO_STATS.Length; i++)
            {
                info.Iv[PO_STATS[i]] = pm.DV[i];
            }
            return info;
        }

        public static Pokemon ToPokemon(this PokemonCustomInfo info)
        {
            var pm = new Pokemon();
            if (info.Identity == 0) return pm;
            var data = SQLiteHelper.Pokemon.GetModel(info.Identity);
            pm.Nickname = info.NickName;
            pm.Num = data.Number;
            pm.Forme = data.Forme;
            pm.Ability = (int)info.Ability;
            pm.Gen = 5;
            pm.Item = SQLiteHelper.Item.GetModel((int)info.Item).POId;
            pm.Gender = (int)info.Gender;
            pm.Hapiness = 255;
            pm.Lvl = info.LV;
            pm.Nature = (int)info.Nature;
            pm.Move = (int[])info.Moves.Clone();
            pm.EV = new int[6];
            pm.DV = new int[6];
            for (int i = 0; i < 6; i++)
            {
                pm.EV[i] = info.Ev[PO_STATS[i]];
                pm.DV[i] = info.Iv[PO_STATS[i]];
            }
            return pm;
        }

        public static string ToString(this PokemonCustomInfo pm)
        {
            var ret = new StringBuilder();
            var data = GameService.GetPokemon(pm.Identity);

            if (string.IsNullOrEmpty(pm.NickName))
            {
                pm.NickName = data.NameBase;
            }
            ret.Append(pm.NickName);
            if (pm.NickName != data.NameBase)
            {
                ret.AppendFormat(" ({0})", data.NameBase);
            }

            if (pm.Gender != PokemonGender.None)
            {
                ret.AppendFormat(" ({0})", pm.Gender == PokemonGender.Male ? "M" : "F");
            }

            if (pm.Item != Item.None)
            {
                ret.Append(" @ " + GameService.GetItem(pm.Item).Name);
            }
            ret.AppendLine();//使用crlf

            ret.AppendLine("Trait: " + GameService.GetAbility(pm.Ability).Name);
            ret.Append("EVs: ");
            string[] stats = { "HP", "Atk", "Def", "Spd", "SAtk", "SDef" };
            int i = 0; bool started = false;
            foreach (int ev in pm.Ev)
            {
                if (ev != 0)
                {
                    if (started) ret.Append(" / ");
                    started = true;
                    ret.Append(ev + " " + stats[i]);
                }
                i++;
            }
            ret.AppendLine();

            //Nature + -
            ret.Append(pm.Nature.ToString() + " Nature");
            int up = pm.Nature.StatBoosted();
            if (up != 0)
            {
                int down = pm.Nature.StatHindered();
                ret.AppendFormat(" (+{0}, -{1})", stats[up], stats[down]);
            }
            ret.AppendLine();

            foreach (var mid in pm.Moves)
            {
                if (mid == 0) continue;
                string name = GameService.GetMove(mid).Name;
                ret.Append("- " + name);
                //Hidden Power
                if (mid == 237)
                {
                    const string HIDE_TYPE = "斗飞毒地岩虫鬼钢火水草电超冰龙恶";
                    ret.AppendFormat(" [{0}]", HIDE_TYPE.Substring((int)pm.Iv.GetHiddenType() - 2, 1));
                }
                ret.AppendLine();
            }

            return ret.ToString();
        }

        public static string ToString(this TeamData team)
        {
            return ToString(team.Pokemons);
        }

        public static string ToString(IEnumerable<PokemonCustomInfo> pokemons)
        {
            var ret = new StringBuilder();

            foreach (var pm in pokemons.Where(p => !p.IsEmpty))
            {
                ret.AppendLine(ToString(pm));
            }
            return ret.ToString().Trim(new char[] { '\r', '\n' });
        }
    }
}
